using NUnit.Framework;
using Tycho.Lexer;
using Tycho.Parser.Peg;
using Tycho.Parser.Tokens;

namespace Tycho.Parser.Tests.Peg {
    [TestFixture]
    public class DelimitedRuleSpecification {
        [Test]
        public void ShouldParseDelimitedTokens () {
            var element = new DelimitedRule<object> (new LiteralRule<object> (new IdentifierTerminal<object> ()), new KeywordRule<object> (","));

            Token [] tokens = NativeLexer.Lex ("a, b, c, d, e").ToArray ();

            var result = element.Parse (tokens, 0, null);
            Assert.IsNotNull (result);
            Assert.AreEqual (9, result.Index);
        }

        [Test]
        public void ShouldOnlyParseUpToLastRule () {
            var element = new DelimitedRule<object> (new LiteralRule<object> (new IdentifierTerminal<object> ()), new KeywordRule<object> (","));

            Token [] tokens = NativeLexer.Lex ("a, b, c, d,").ToArray ();

            var result = element.Parse (tokens, 0, null);
            Assert.IsNotNull (result);
            Assert.AreEqual (7, result.Index);
        }

        [Test]
        public void ShouldReturnNullIfParseNotMatched () {
            var element = new DelimitedRule<object> (new NamedRule<object> ("a", new IdentifierTerminal<object> ()), new KeywordRule<object> (","));

            Token [] tokens = NativeLexer.Lex ("8, b, c, d,").ToArray ();

            var term = element.Parse (tokens, 0, null);
            Assert.IsNull (term);
        }

        [Test]
        public void ShouldPassThroughContextFromItemToDelimiter () {
            IdentifierTerminal<int> id = new IdentifierTerminal<int> ();
            id.Action = (term, i) => i + 1;
            KeywordTerminal<int> keyword = new KeywordTerminal<int> (",");
            keyword.Action = (term, i) => i + 1;
            var element = new DelimitedRule<int> (new LiteralRule<int> (id), new LiteralRule<int> (keyword));

            Token [] tokens = NativeLexer.Lex ("a, b, c, d").ToArray ();

            var result = element.Parse (tokens, 0, 0);
            Assert.AreEqual (7, result.Context);
        }

        [Test]
        public void ShouldReturnAllCaptures () {
            var rule = new DelimitedRule<object> (new NamedRule<object> ("item", new IdentifierTerminal<object> ()), new NamedRule<object> ("delimiter", new IdentifierTerminal<object> ()));

            Token [] tokens = NativeLexer.Lex ("a, b").ToArray ();

            var result = rule.Parse (tokens, 0, 0);
            Assert.AreEqual (3, result.Captures.Count);
            result.AssertCaptureIs (0, "item", "a");
            result.AssertCaptureIs (1, "delimiter", ",");
            result.AssertCaptureIs (2, "item", "b");
        }
    }
}